package mining;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

public class Itemset {
	public static int numUniqueItems = Integer.MIN_VALUE;
	public static int numOverSupportItems = Integer.MIN_VALUE;
	public static int[] actualToConverted;
	public static int[] convertedToActual;

	public boolean[] itemset;
	public int numItems = Integer.MIN_VALUE;

	public static Vector<Integer> removeBelowSup(Vector<Integer> itemFreqs, int minSupport) {
		actualToConverted = new int[itemFreqs.size()];
		Arrays.fill(actualToConverted , -1);
		int numOverMin = 0;
		for (int i = 0; i < itemFreqs.size(); i++) {
			if (itemFreqs.get(i) >= minSupport) {
				actualToConverted[i] = numOverMin++; 
			}
		}
		convertedToActual = new int[numOverMin];
		Vector<Integer> newItemFreqs = new Vector<Integer>();
		newItemFreqs.setSize(convertedToActual.length);
		for (int i = 0, j = 0; i < actualToConverted.length; i++) {
			int actual = actualToConverted[i]; 
			if (actual != -1) {
				convertedToActual[j] = i;
				newItemFreqs.set(j, itemFreqs.get(i));
				j++;
			}
		}
		
		numUniqueItems = actualToConverted.length;
		numOverSupportItems = convertedToActual.length;
		
		return newItemFreqs;
	}
	
	public static Itemset newEmptyItemset() {
		Itemset ni = new Itemset();
		ni.itemset = new boolean[numOverSupportItems];
		return ni;
	}

	private Itemset() {
	}

	public Itemset(List<Integer> itemList) {
		if (itemList.isEmpty()) {
			throw new RuntimeException("itemList is empty");
		}
		if (numUniqueItems == Integer.MIN_VALUE) {
			throw new RuntimeException("class is not ready to be used");
		}
		// System.out.println("construting new Itemset: " + itemList);
		this.itemset = new boolean[numOverSupportItems];
		// Itemset.print(itemset);
		for (int item : itemList) {
			// int itemPosition = mapping1.get(item);
			// itemset[itemPosition] = true;
			this.itemset[item] = true;
		}
		this.numItems = itemList.size();
		// Itemset.print(itemset);
	}

	public int size() {
		return this.numItems;
	}

	public int maxSize() {
		return numOverSupportItems;
	}

	public Itemset(int item) {
		this.itemset = new boolean[numOverSupportItems];
		this.itemset[item] = true;
		this.numItems = 1;
	}

	/**
	 * Careful using this - does not adjust numItems automatically
	 * 
	 * @param item
	 * @param value
	 */
	public void set(int item, boolean value) {
		this.itemset[item] = value;
	}

	public boolean get(int item) {
		return this.itemset[item];
	}
	
	public boolean containsAny(int[] items) {
		for (int item : items) {
			if (this.itemset[item])
				return true;
		}
		return false;
	}

	public boolean remove(int item) {
		if (this.itemset[item] == true) {
			this.numItems--;
			this.itemset[item] = false;
			return true;
		}
		return false;
	}

	/**
	 * Returns true iff item does not already exist in the itemset.
	 * 
	 * @param item
	 * @return
	 */
	public boolean add(int item) {
		if (this.itemset[item] == false) {
			this.numItems++;
			this.itemset[item] = true;
			return true;
		}
		return false;
	}

	public String toString() {
		StringBuilder output = new StringBuilder();
		output.append("[");
		for (int i = 0, j = 1; i < this.itemset.length; i++) {
			if (this.itemset[i]) {
				output.append(i);
				if (j++ < this.numItems)
					output.append(", ");
			}
		}
		output.append("]");
		return output.toString();
	}

	void print() {
		print(this.itemset);
	}

	static void print(boolean[] bools) {
		for (int i = 0; i < bools.length; i++) {
			if (bools[i] == false)
				System.out.print(0);
			else
				System.out.print(1);
		}
		System.out.println();
	}

	public boolean hasSubset_modified(int[] subset) {
		for (int i : subset) {
			if (!this.itemset[i])
				return false;
		}
		return true;
	}

	public boolean hasSubset(Itemset subset) {
		for (int i = 0; i < numOverSupportItems; i++) {		// itemcount == zg.itemset.length
			if (subset.itemset[i] && !this.itemset[i]) {
				return false;
			}
		}
		return true;
	}

	public Itemset copy() {
		boolean[] boolArr = new boolean[Itemset.numOverSupportItems];
		System.arraycopy(this.itemset, 0, boolArr, 0, Itemset.numOverSupportItems);
		Itemset newCopy = new Itemset();
		newCopy.itemset = boolArr;
		newCopy.numItems = this.numItems;

		return newCopy;
	}

	public int hashCode() {
		return Arrays.hashCode(this.itemset);
	}

	@Override
	public boolean equals(Object o) {
		if (o.getClass() != this.getClass()) {
			return false;
		} else {
			return Arrays.equals(this.itemset, ((Itemset) o).itemset);
		}
	}

	public List<Itemset> nMinus1Subsets() {
		List<Itemset> result = new ArrayList<Itemset>(this.numItems);

		int[] itemIndexes = new int[this.numItems];
		for (int i = 0, j = 0; i < Itemset.numOverSupportItems; i++) {
			if (this.itemset[i])
				itemIndexes[j++] = i;
		}

		for (int i = 0; i < this.numItems; i++) {
			Itemset subset = this.copy();
			subset.remove(itemIndexes[i]);
			result.add(subset);
		}

		return result;
	}

	public List<Integer> converToList() {
		List<Integer> result = new ArrayList<Integer>();
		for (int i = 0; i < numOverSupportItems; i++) { // itemcount ==
													// itemset.itemset.length
			if (this.itemset[i] == true) {
				result.add(i);
			}
		}
		return result;
	}

	public int[] convertToArray() {
		int[] result = new int[this.numItems];
		int count = 0;
		for (int i = 0; i < Itemset.numOverSupportItems; i++) {
			if (this.itemset[i])
				result[count++] = i;
		}
		return result;
	}

	public Set<Integer> convertToSet() {
		Set<Integer> result = new HashSet<Integer>();
		for (int i = 0; i < numOverSupportItems; i++) {
			if (this.itemset[i]) {
				result.add(i);
			}
		}
		return result;
	}

	public static Itemset findAllItems(Object[] a) {
		Itemset items = ((Itemset) a[0]).copy();
		List<Integer> empties = new ArrayList<Integer>();
		for (int i = 1; i < items.maxSize(); i++) {
			if (!items.get(i)) {
				empties.add(i);
			}
		}
		for (int i = 1; i < a.length; i++) {
			int empty;
			for (Iterator<Integer> it = empties.iterator(); it.hasNext();) {
				empty = it.next();
				if (((Itemset) a[i]).get(empty)) {
					items.add(empty);
					it.remove();
				}
			}
			if (empties.isEmpty())
				break;
		}

		return items;
	}

}
